package dev.ideas.funkyj.group;

import java.util.*;

/**
 */
class _Group {

    abstract static class Element<T> {
        final Root<T> root;
        Element(Root<T> root) { this.root = root; }
        abstract Element<T> process(T t);
    }

    static class Root<T> {
        final Iterator<T> iterator;
        Node<?, ?, T> node;
        Root(Iterator<T> iterator) { this.iterator = iterator; }

        boolean hasNext() { return iterator.hasNext(); }
        void next() {
            final T next = iterator.next();
            Element<T> process = node;
            while (process != null) { process = process.process(next); }
        }
    }

    abstract static class Leaf<T> extends Element<T> {
        final List<T> cache = new ArrayList<T>();
        Leaf(Root<T> root) { super(root); }
        @Override _Group.Element<T> process(T t) { cache.add(t); return null; }
    }

    abstract static class Node<K, V extends Element<T>, T> extends Element<T> {
        final Map<K, V> map = new HashMap<K, V>();

        /*case Root*/ Node(Iterator<T> iterator) { super(new Root<T>(iterator)); root.node = this; }
        /*case Node*/ Node(Root<T> root) { super(root); }

        abstract K key(T t);
        abstract V create();

        @Override final Element<T> process(T t) { return get(key(t)); }

        final V get(K k) {
            V i = map.get(k);
            if (i == null) { map.put(k, i = create()); }
            return i;
        }
    }
}
